#ifdef __APPLE__
        #include <OpenGL/gl.h>
        #include <OpenGL/glu.h>
        #include <GLUT/glut.h>
#else
	#ifdef _WIN32
        #include "../glut.h"
	#else
        #include <GL/gl.h>
        #include <GL/glu.h>
        #include <GL/glut.h>
	#endif
#endif

#include <iostream>
#include <limits.h>

#include "../inc/Polygone.h"
#include "../inc/Segment.h"

using namespace std;

void displayString(QString _s, int _x, int _y)
{
	int i2 = 0;
	QByteArray _string = _s.toAscii();
	
	glColor3f(1,0,0);
	glPixelZoom(1.0,1.0);
	for ( int i = 0 ; i < (int)_s.size() ; i++ )
	{
		if ( (int)_string[i] == '\n' )
			_y -= 13;
		
		else
		{
			i2++;
			glRasterPos2i(  _x + (i2*8) , _y );
			glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int)_string[i] );
		}
	}
}

Polygone::Polygone()
{
	nbPts = 0;
	list.clear();
}

Polygone::~Polygone()
{
	
}

Polygone::Polygone(const Polygone &_pol)
{
	cout<<endl<<"Dans le constructeur de copie de polygone"<<endl<<endl;
	nbPts = 0;
	
	cout<<"Nombre de points de pol :"<<_pol.nbPts<<endl<<endl;
	
	for ( int i = 0 ; i < _pol.nbPts ; i++ )
	{
		this->addPoint(_pol.list[i]);
		cout<<endl<<"Add "<<i<<" fait"<<endl;
	}
	
	cout<<"Nombre de points de pol :"<<_pol.nbPts<<endl<<endl;
	
	cout<<endl;
}

int Polygone::getNbPts()
{
	return nbPts;
}

Point* Polygone::getPoint(int _i)
{
	Point* rslt = list[_i];
	return rslt;
}

Polygone Polygone::operator=( const Polygone &_p)
{
	Polygone rslt;
	
	for ( int i = 0 ; i < _p.nbPts ; i++ )
	{
		rslt.addPoint(_p.list[i]);
	}
	
	return rslt;
}

bool Polygone::isEmpty()
{
	return ( nbPts == 0 );
}

void Polygone::addPoint(Point* _p)
{
	list.push_back ( _p );
	nbPts++;
}

bool Polygone::find(Point *_p)
{
	for ( int i = 0 ; i < (int)list.size() ; i++ )
		if ( list[i] == _p )
			return true;
	
	return false;
}

void Polygone::deleteLastPoint()
{
	list.pop_back();
	nbPts--;
}

void Polygone::deletePoint(Point *_p)
{
	for ( int i = 0 ; i < (int)list.size() ; i++ )
	{
		if ( list[i] == _p )
		{
			list.erase( list.begin() + i );
			nbPts--;
			return;
		}
	}
}

void Polygone::replacePoint(Point *_p1, Point *_p2)
{
	/* Si les deux points sont dans le même polygone */
	if ( this->find(_p1) && this->find(_p2) ) 
	{
		this->deletePoint(_p1);
	}
	
	else
	{
		for ( int i = 0 ; i < (int)list.size() ; i++ )
		{
			if ( list[i] == _p1 )
			{
				free( list[i] );
				list[i] = _p2;
				return;
			}
		}
	}
}

void Polygone::clear()
{
	nbPts = 0;
	this->list.clear();
}

void Polygone::print()
{
	cout<<"Polygone a "<<nbPts<<" points : "<<endl;
	
	for ( int i = 0 ; i < nbPts ; i++ )
	{
		cout<<"\t";
		list[i]->print();
		cout<<endl;
	}
}

void Polygone::display()
{
	glBegin(GL_LINE_LOOP);
		for ( int i = 0 ; i < (int)list.size() ; i++ )
			glVertex2i ( (int)list[i]->getX(), (int)list[i]->getY() );
	glEnd();
}

void Polygone::display(float _r, float _g, float _b)
{
	glColor3f(_r,_g,_b);
	
	glBegin(GL_LINE_LOOP);
		for ( int i = 0 ; i < (int)list.size() ; i++ )
			glVertex2i ( (int)list[i]->getX(), (int)list[i]->getY() );
	glEnd();
}

void Polygone::displayFilled(float _r, float _g, float _b)
{
	glColor3f(_r,_g,_b);
	
	glBegin(GL_POLYGON);
		for ( int i = 0 ; i < (int)list.size() ; i++ )
			glVertex2i ( (int)list[i]->getX(), (int)list[i]->getY() );
	glEnd();
}

void Polygone::displayFilled(float _r, float _g, float _b, float _a)
{
	glColor4f(_r,_g,_b,_a);
	
	glBegin(GL_POLYGON);
		for ( int i = 0 ; i < (int)list.size() ; i++ )
		{
			glVertex2i ( list[i]->getX(), list[i]->getY() );
		}
	glEnd();
}

void Polygone::displayPoints(float _r, float _g, float _b)
{
	glColor3f(_r,_g,_b);
	
	glBegin(GL_POINTS);
		for ( int i = 0 ; i < (int)list.size() ; i++ )
			glVertex2i ( (int)list[i]->getX(), (int)list[i]->getY() );
	glEnd();
}

void Polygone::displayText(QString _s)
{
	int posX = 0, posY = 0;
	
	for ( int i = 0 ; i < nbPts ; i++ )
	{
		posX += list[i]->getX();
		posY += list[i]->getY();
	}
	
	posX /= nbPts;
	posY /= nbPts;
	
	displayString( _s, posX, posY );
}

void Polygone::displayPions( int _nbPions, Image _i)
{
	if ( _nbPions != 0 )
	{
		int posX = 0, posY = 0;
		
		for ( int i = 0 ; i < nbPts ; i++ )
		{
			posX += list[i]->getX();
			posY += list[i]->getY();
		}
		
		posX /= nbPts;
		posY /= nbPts;
		
		posX -= (_nbPions/3) * _i.getWidth();
		
		if ( _nbPions%3 == 0 )
			posX += _i.getWidth();
		
		for ( int i = 0 ; i < _nbPions ; i++ )
		{
			if ( i != 0 && i % 3 == 0 )
				posX += _i.getWidth() + 20;
			
			_i.display(posX - (i%3)*(_i.getWidth()/2), posY - (i%3)*(_i.getHeight()/2) );
		}
	}
}

bool Polygone::contains(Point *_p)
{
	int nbInter = 0;
	
	Point p1 ( _p->getX(), _p->getY() );
	Point p2( INT_MAX, _p->getY() );
	
	Segment s1(p1, p2);
	
	if ( (int)list.size() > 2 )
	{
		for ( int i = 0 ; i < (int)list.size() - 1 ; i++ )
		{	
			Point q1( list[i]->getX(), list[i]->getY() );
			Point q2( list[i+1]->getX(), list[i+1]->getY() );
			
			Segment s2(q1,q2);
			
			if ( s1.intersect(s2) )
				nbInter++;
		}
		
		Point q1( list[(int)list.size()-1]->getX(), list[(int)list.size()-1]->getY() );
		Point q2( list[0]->getX(), list[0]->getY() );
		
		Segment s2(q1,q2);
		
		if ( s1.intersect(s2) )
			nbInter++;
		
		if ( nbInter % 2 == 0 )
			return false;
		
		else return true;
	}
	
	else return false;
}

bool Polygone::contains(int _x, int _y)
{
	int nbInter = 0;
	Point p1(_x, _y);
	Point p2( INT_MAX, _y );
	Segment s1(p1, p2);
	
	if ( (int)list.size() > 2 )
	{
		for ( int i = 0 ; i < (int)list.size() - 1 ; i++ )
		{	
			Point q1( list[i]->getX(), list[i]->getY() );
			Point q2( list[i+1]->getX(), list[i+1]->getY() );
			
			Segment s2(q1,q2);
			
			if ( s1.intersect(s2) )
				nbInter++;
		}
		
		Point q1( list[(int)list.size()-1]->getX(), list[(int)list.size()-1]->getY() );
		Point q2( list[0]->getX(), list[0]->getY() );
		
		Segment s2(q1,q2);
		
		if ( s1.intersect(s2) )
			nbInter++;
		
		if ( nbInter % 2 == 0 )
			return false;
		
		else return true;
	}
	
	else return false;
}
